/******************************************************************************
Project    : Real time rtsp server library base on live555
*******************************************************************************
File Name    :  <VideoRTimeFramedSource.cpp>:  video real time framed source source file
Module Name  :  
Description  :  None
History      :
 No.   Ver.     Date        Designed by  Comment
-----+--------+----------+------------+---------------------------------------
 001   0.00.01  05/25/2015  <3G@LIURENHUA>   <video real time framed source source file>
*******************************************************************************/
#include "VideoRTimeFramedSource.h"

/******************************************************************************
  macro define
 ******************************************************************************/
//#define FRAME_DEBUG
#ifdef FRAME_DEBUG
#include <utils/Log.h>
#endif /* FRAME_DEBUG */

/******************************************************************************
  class functions define
 ******************************************************************************/
VideoRTimeFramedSource::VideoRTimeFramedSource(
							UsageEnvironment & env,
#ifdef LOCAL_SOCK_INPUT
							const char  *pcIdentity,
#endif /* LOCAL_SOCK_INPUT */
							const u_int8_t ucFrmRate,
#ifdef LOCAL_SOCK_INPUT
							const u_int32_t unSBufSize,
							const u_int32_t unRBufSize
#else
							queue_t *pstQue
#endif /* LOCAL_SOCK_INPUT */ 
							) : FramedSource(env)
{
#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "VideoRTimeFramedSource\n");
#endif /* FRAME_DEBUG */

	/* Clear class members */
#ifdef LOCAL_SOCK_INPUT
	pstServer = NULL;
#else
	m_que = pstQue;
#endif /* LOCAL_SOCK_INPUT */

	/* Get frame rate of video stream */
	m_unFrmRate = ucFrmRate;
	m_unLeftTime = 0;

#ifdef LOCAL_SOCK_INPUT
	/* Initialize local udp socket with identity */
	if(LSOCK_ERR_NOERR != 
		eInitLocalUdpSocket(&pstServer, pcIdentity,
		LSOCK_TYPE_S, unSBufSize, unRBufSize)){
		printf("[%s]initialize local udp socket failed\n", 
			__func__);
		return;
	}
#endif /* LOCAL_SOCK_INPUT */

#ifdef SAVE_FILE_ENB
    char fileName[32];
    snprintf(fileName, 32, "/sdcard/queue_%p",  pstQue);
	fd = open(fileName, O_CREAT | O_WRONLY | O_TRUNC, 0655);
#endif /* SAVE_FILE_ENB */
}

VideoRTimeFramedSource::~VideoRTimeFramedSource()
{
#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "~VideoRTimeFramedSource\n");
#endif /* FRAME_DEBUG */
	
#ifdef LOCAL_SOCK_INPUT
	if( (NULL != pstServer) ){
		vDInitLocalUdpSocket(pstServer);
		pstServer = NULL;
	}
#endif /* LOCAL_SOCK_INPUT */

#ifdef SAVE_FILE_ENB
    if( (fd > 0) ){::close(fd);}
#endif /* SAVE_FILE_ENB */
}

#ifdef NOCARE_FRM_RATE
#else
void VideoRTimeFramedSource::getNextFrame(void * clientData)
{
#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "getNextFrame\n");
#endif /* FRAME_DEBUG */
	((VideoRTimeFramedSource *)clientData)->GetFrameData();
}
#endif /* NOCARE_FRM_RATE */

void VideoRTimeFramedSource::doGetNextFrame()
{
#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "doGetNextFrame\n");
#endif /* FRAME_DEBUG */
#ifdef NOCARE_FRM_RATE
	GetFrameData();
#else
	/* Calculate wait time with frame rate */
	double delay = 1000.0 / m_unFrmRate;	// ms
	int to_delay = delay * 1000;			// us
	nextTask() = 
#ifdef SCHED_NODELAY
		envir().taskScheduler().scheduleDelayedTask(
		0, (TaskFunc*)getNextFrame, this);
#else
		envir().taskScheduler().scheduleDelayedTask(
		to_delay, (TaskFunc*)getNextFrame, this);
#endif /* SCHED_NODELAY */
#endif /* NOCARE_FRM_RATE */
}

void VideoRTimeFramedSource::GetFrameData()
{
	/* Initialize require read size */
	int read = fMaxSize;
	fFrameSize = 0;
	
#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", "GetFrameData\n");
#endif /* FRAME_DEBUG */

#ifdef LOCAL_SOCK_INPUT	
	/* Receive encode data from encoder */
	if( (LSOCK_ERR_NOERR == 
		eRecvDataByLUdpSock(pstServer, fTo, &read)) ){
		if( (read <= 0) ){
			printf("[%s]no data = %d\n", __func__, read);
			fNumTruncatedBytes = 0;
			return;
		}
	}else{
		printf("[%s]receive data failed from local socket\n", 
			__func__);
		fNumTruncatedBytes = 0;
		return;
	}
#else
	//ALOGD("start pop data");
	AVPacket *pkt = (AVPacket *)q_pop_tail(m_que);
	if( (NULL != pkt) ){
#ifdef FRAME_DEBUG
		__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", 
			"pop data size[%d]\n" , pkt->size);
#endif /* FRAME_DEBUG */
		if( (pkt->size <= read) ){
			fNumTruncatedBytes = 0;
			read = pkt->size;
		}else{
			fNumTruncatedBytes = pkt->size - read;
		}
		//ALOGD("end pop data");
		if( (NULL != pkt->data) ){
			memcpy(fTo, pkt->data, read);
			free(pkt->data);
		}
		free(pkt);
	}else{
		fNumTruncatedBytes = 0;
		return;
	}
#endif /* LOCAL_SOCK_INPUT */

#ifdef FRAME_DEBUG
	__android_log_print(ANDROID_LOG_DEBUG, 
			"RtspServerInterface", 
			"Receive data end[%d]\n", read);
#endif /* FRAME_DEBUG */

	/* Set frame size and truncated bytes */
#ifdef LOCAL_SOCK_INPUT
	fNumTruncatedBytes = 0;
#endif /* LOCAL_SOCK_INPUT */
	fFrameSize = read;
	
#ifdef SAVE_FILE_ENB
    if( (fd > 0) && (read > 0) ){write(fd, fTo, read);}
#endif /* SAVE_FILE_ENB */
	
	/* Update presentation time with frame rate */
	if ( (fPresentationTime.tv_sec == 0 
	 	&& fPresentationTime.tv_usec == 0) ) {
	 	/* This is the first frame, so use the current time */
	 	gettimeofday(&fPresentationTime, NULL);
	}else{
		unsigned uSumVal = m_unLeftTime + 1000000;
		unsigned uSeconds = fPresentationTime.tv_usec 
			+ (uSumVal / m_unFrmRate);
		m_unLeftTime = uSumVal % m_unFrmRate;
		fPresentationTime.tv_sec += uSeconds/1000000;
		fPresentationTime.tv_usec = uSeconds%1000000;
	}
	fDurationInMicroseconds = 1000000.0 / m_unFrmRate;
	
#ifdef NOCARE_FRM_RATE
 	nextTask() = 
 		envir().taskScheduler().scheduleDelayedTask(0,
		(TaskFunc*)FramedSource::afterGetting, this);
#else
	/* It is read successfully */
	afterGetting(this);
#endif /* NOCARE_FRM_RATE */
}
